package com.hmsm.dingtalk;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.dingtalk.open.client.api.model.corp.SnsPersistentCode;
import com.dingtalk.open.client.api.model.corp.SnsToken;
import com.dingtalk.open.client.api.service.corp.SnsService;
import com.hmsm.dingtalk.openapi.AppConfig;
import com.hmsm.dingtalk.openapi.EnterpriseConfig;
import com.hmsm.dingtalk.openapi.auth.AuthHelper;
import com.hmsm.server.util.URLHelp;

import net.sf.json.JSONObject;

public class DingTalkClient {

	private static final Log log = LogFactory.getLog(DingTalkClient.class);

	public static final String CONS_CorpID = "CorpID";
	public static final String CONS_CorpSecret = "CorpSecret";
	public static final String CONS_SSOSecret = "SSOSecret";

	public static final String CONS_AppID = "AppID";
	public static final String CONS_AppSecret = "AppSecret";

	public static final String CONS_AgentID = "AgentID";

	public static final String CONS_RelevanceDepartment = "RelevanceDepartment";

	private static final Map<String, DingTalkClient> clientMap = new HashMap<String, DingTalkClient>();

	private final EnterpriseConfig enterpriseConfig;

	private AppConfig appConfig;

	public AppConfig getAppConfig() {
		return appConfig;
	}

	private String rootDepartPath;

	public String getRootDepartPath() {
		return rootDepartPath;
	}

	public void setRootDepartPath(String rootDepartPath) {
		this.rootDepartPath = rootDepartPath;
	}

	public String getTicket() throws Exception, Exception {
		return AuthHelper.getJsapiTicket(AuthHelper.getAccessToken(enterpriseConfig), enterpriseConfig);
	}

	public String getAppId() {
		String appId = null;
		if (appConfig != null) {
			appId = appConfig.getAppId();
		}
		return appId;
	}

	public String getCorpId() {
		return enterpriseConfig.getCorpId();
	}

	private String appSecret;

	public String getAppSecret() {
		return appSecret;
	}

	private DingTalkClient(String corpid, String corpsecret, String ssoSecret) {
		this.enterpriseConfig = new EnterpriseConfig(corpid, corpsecret, ssoSecret);
	}

	public static DingTalkClient getInstance(String corpid, String corpsecret, String ssoSecret) {
		DingTalkClient client = null;

		if (corpid != null) {
			if (clientMap.containsKey(corpid)) {
				client = clientMap.get(corpid);
			} else {
				client = new DingTalkClient(corpid, corpsecret, ssoSecret);
				clientMap.put(corpid, client);
			}
		}

		return client;
	}

	/**
	 * 
	 * @param relevanceConfig
	 * @return
	 */
	public static DingTalkClient getInstance(String relevanceConfig) {
		DingTalkClient instance = null;

		JSONObject jsonResult = JSONObject.fromObject(relevanceConfig);

		String corpid = null;
		if (jsonResult.containsKey(CONS_CorpID)) {
			corpid = jsonResult.getString(CONS_CorpID);
		}
		String corpSecret = null;
		if (jsonResult.containsKey(CONS_CorpSecret)) {
			corpSecret = jsonResult.getString(CONS_CorpSecret);
		}
		String ssoSecret = null;
		if (jsonResult.containsKey(CONS_SSOSecret)) {
			ssoSecret = jsonResult.getString(CONS_SSOSecret);
		}
		String rootDepartPath = null;
		if (jsonResult.containsKey(CONS_RelevanceDepartment)) {
			rootDepartPath = jsonResult.getString(CONS_RelevanceDepartment);
		}
		String appId = null;
		if (jsonResult.containsKey(CONS_AppID)) {
			appId = jsonResult.getString(CONS_AppID);
			if (appId != null && appId.length() == 0) {
				appId = null;
			}
		}
		String agentId = null;
		if (jsonResult.containsKey(CONS_AgentID)) {
			agentId = jsonResult.getString(CONS_AgentID);
		}
		String appSecret = null;
		if (jsonResult.containsKey(CONS_AppSecret)) {
			appSecret = jsonResult.getString(CONS_AppSecret);
		}

		instance = getInstance(corpid, corpSecret, ssoSecret);
		if (instance != null) {
			instance.setRootDepartPath(rootDepartPath);
			instance.setAppConfig(new AppConfig(appId, appSecret));
			instance.setAgentId(agentId);
		}

		return instance;
	}

	private void setAppConfig(AppConfig appConfig2) {
		this.appConfig = appConfig2;
	}

	private void setAgentId(String agentId) {
		enterpriseConfig.setAgentId(agentId);
	}

	public String doPost(String url, Map<String, String> map, String charset) {
		HttpClient httpClient = null;
		HttpPost httpPost = null;
		String result = null;
		try {
			httpClient = new SSLClient();
			httpPost = new HttpPost(url);
			// 设置参数
			List<NameValuePair> list = new ArrayList<NameValuePair>();
			Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, String> elem = (Entry<String, String>) iterator.next();
				list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
			}
			if (list.size() > 0) {
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, charset);
				httpPost.setEntity(entity);
			}
			HttpResponse response = httpClient.execute(httpPost);
			if (response != null) {
				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					result = EntityUtils.toString(resEntity, charset);
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}

	public Department getDeptTree(String rootDepartPath) throws Exception {
		Department dept = null;

		Department department = null;

		URLHelp help = new URLHelp();

		String result = help.requestRul(EnterpriseConfig.OAPI_HOST + "/department/list?access_token=" + AuthHelper.getAccessToken(enterpriseConfig) + "", "GET", "UTF-8");

		JSONObject jsonResult = JSONObject.fromObject(result);

		Map<Long, Department> deptMap = new HashMap<Long, Department>();
		Map<String, User> userMap = new HashMap<String, User>();
		if (jsonResult.containsKey("errcode")) {
			if (jsonResult.getInt("errcode") == 0) {
				net.sf.json.JSONArray deptJsonArray = jsonResult.getJSONArray("department");
				department = new Department();
				department.setId(0L);
				department.setName("组织机构");
				department.setSubDepartments(new ArrayList<Department>());
				deptMap.put(department.getId(), department);

				// 生成部门对象
				for (int i = 0; i < deptJsonArray.size(); i++) {
					net.sf.json.JSONObject obj = (net.sf.json.JSONObject) deptJsonArray.get(i);
					Department subDept = new Department();
					subDept.setId(obj.getLong("id"));
					subDept.setName(obj.getString("name"));
					subDept.setCreateDeptGroup(obj.getBoolean("createDeptGroup"));
					subDept.setAutoAddUser(obj.getBoolean("autoAddUser"));
					deptMap.put(subDept.getId(), subDept);
				}

				// 装配部门树
				for (int i = 0; i < deptJsonArray.size(); i++) {
					net.sf.json.JSONObject obj = (net.sf.json.JSONObject) deptJsonArray.get(i);
					Department subDept = deptMap.get(obj.getLong("id"));

					Department parent = department;
					if (obj.containsKey("parentid")) {
						long parentId = obj.getLong("parentid");
						if (deptMap.containsKey(parentId)) {
							parent = deptMap.get(parentId);
						}
					}
					subDept.setParent(parent);
					if (parent.getSubDepartments() == null) {
						parent.setSubDepartments(new ArrayList<Department>());
					}
					parent.getSubDepartments().add(subDept);
				}

				dept = department;
				if (department != null && department.getSubDepartments().size() == 1) {
					dept = department.getSubDepartments().get(0);
				}
				if (rootDepartPath != null) {
					for (String deptName : rootDepartPath.split("\\\\")) {
						if (deptName != null && deptName.length() > 0 && dept != null && dept.getSubDepartments() != null) {
							for (Department subDept : dept.getSubDepartments()) {
								if (deptName != null && deptName.equals(subDept.getName())) {
									dept = subDept;
									break;
								}
							}
						}
					}
				}
			} else {
				log.warn("调用失败：" + jsonResult.getString("errmsg"));
			}
		}

		// 加载部门用户
		loadDepartmentUsers(dept, deptMap, userMap);

		return dept;
	}

	private void loadDepartmentUsers(Department dept, Map<Long, Department> deptMap, Map<String, User> userMap) throws Exception {
		if (dept != null) {

			URLHelp help = new URLHelp();

			String result;
			try {
				result = help.requestRul(
						EnterpriseConfig.OAPI_HOST + "/user/list?access_token=" + AuthHelper.getAccessToken(enterpriseConfig) + "&department_id=" + dept.getId() + "&fetch_child=0",
						"GET", "UTF-8");
			} catch (Exception e) {
				e.printStackTrace();
				result = null;
			}

			JSONObject jsonResult = JSONObject.fromObject(result);

			if (jsonResult.containsKey("errcode")) {
				if (jsonResult.getInt("errcode") == 0) {
					net.sf.json.JSONArray jsonArray = jsonResult.getJSONArray("userlist");

					for (int i = 0; i < jsonArray.size(); i++) {
						JSONObject obj = (JSONObject) jsonArray.get(i);
						User user = (User) JSONObject.toBean(obj, User.class);//
						if (userMap.containsKey(user.getDingId())) {
							user = userMap.get(user.getDingId());
						} else {
							user.setCorpId(enterpriseConfig.getCorpId());
							userMap.put(user.getDingId(), user);
						}

						Department mainDepartment = null;
						for (Object deptId : user.getDepartment()) {
							Long id = new Long((Integer) deptId);
							if (deptMap.containsKey(id)) {
								Department department = deptMap.get(id);
								if (department != null) {
									if (!department.getId().equals(dept.getId())) {
										mainDepartment = department;
									}
								}
							}
						}
						if (mainDepartment == null) {
							mainDepartment = dept;
						}
						if (mainDepartment.getMember() == null) {
							mainDepartment.setMember(new ArrayList<User>());
						}
						User addUser = user;
						for (User u : mainDepartment.getMember()) {
							if (u.getDingId().equals(user.getDingId())) {
								addUser = null;
								break;
							}
						}
						if (addUser != null) {
							mainDepartment.getMember().add(addUser);
						}
					}
				} else {
					log.warn("调用失败：" + jsonResult.getString("errmsg"));
				}
			}
		}
		if (dept.getSubDepartments() != null) {
			for (Department subDept : dept.getSubDepartments()) {
				loadDepartmentUsers(subDept, deptMap, userMap);
			}
		}
	}

	/**
	 * 获取关联的部门树
	 * 
	 * @return
	 * @throws Exception
	 */
	public Department getRelevanceDeptTree() throws Exception {
		return getDeptTree(rootDepartPath);
	}

	public Department getDeptTree() throws Exception {
		return getDeptTree(null);
	}

	public User getUserInfo(SnsToken snsToken) {
		User user = null;

		URLHelp help = new URLHelp();

		String interfaceStr = "/sns/getuserinfo?sns_token=" + snsToken.getSns_token();
		String result;
		try {
			result = help.requestRul(EnterpriseConfig.OAPI_HOST + interfaceStr, "GET", "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
			result = "";
		}
		JSONObject jsonResult = JSONObject.fromObject(result);

		if (jsonResult.containsKey("errcode")) {
			if (jsonResult.getInt("errcode") == 0 && jsonResult.containsKey("user_info")) {
				JSONObject userObje = jsonResult.getJSONObject("user_info");
				user = new User();
				user.setDingId(userObje.getString("dingId"));
				user.setOpenId(userObje.getString("openid"));
				log.debug("调用成功：" + jsonResult.getString("errmsg"));
			} else {
				log.warn("调用失败：" + jsonResult.getString("errmsg"));
			}
		}
		return user;
	}

	public String getSignature(String url, String nonceStr, long timeStamp) throws Exception, Exception {
		return AuthHelper.sign(getTicket(), nonceStr, timeStamp, url);
	}

	public String getAgentId() {
		return enterpriseConfig.getAgentId();
	}

	public SnsPersistentCode getPersistentCode(String loginTmpCode) throws Exception {
		SnsPersistentCode persistentCode = null;

		String appToken = AuthHelper.getAppToken(appConfig);
		SnsService snsService = new HmsmSnsService();
		persistentCode = snsService.getPersistentCode(appToken, loginTmpCode);

		return persistentCode;
	}

	public SnsToken getSnsToken(SnsPersistentCode persistentCode) throws Exception {
		SnsToken snsToken = null;

		SnsService snsService = new HmsmSnsService();
		snsToken = snsService.getSnsToken(AuthHelper.getAppToken(appConfig), persistentCode.getOpenid(), persistentCode.getPersistent_code());

		return snsToken;
	}

}
